// const Util = require('./Util')
// const fs = require('fs')

const xLen = 4
const yLen = 20
const keyword = 'abcdefghijklmnopqrstuvwxyz'
/** x,y二维数据组，y为组，x为组内元素 */
const arr = new Array(yLen).fill(0).map((_y, yIdx) => new Array(xLen).fill(0).map((_x, xIdx) => `${keyword[yIdx]}${xIdx}`))

const tableNameByResult = 'Creator_Result'
const tableNameByGroupLib = 'Creator_GroupLib'
/** 最大可重复元素 */
let maxSame = 3

/** nft图片生成函数
 * 已知有y组配饰，每组有x张不等的图片资源，需从每个y中抽一个x组成一个船新的数据进行图片导出
 * 条件1：x拥有不同稀有度
 * 条件2：导出的数据中，每条数据不能与其他数据拥有z个以上相同的x
 *
 * 实现：
 *  1. 读取文件夹生成配置
 *  2. 手动调整配置，如图片宽高，每张x的稀有度等
 *  3. 求取固定图片z的所有集合，并将其组合数据{group: id[], groupPath: number[], exhausted: boolean}
 *  4. 从集合中抽取一条exhausted===false的数据，并将其作为固定图片
 *  5. 计算其他图片，计算时，其他图片的x坐标不能等于任一历史数据的x坐标，若无法算得x，则代表此条数据计算完毕
 *  6. 循环4，5 直至集合计算完毕
 */
class Creator {
  lengthY = 0
  /** 传入配置
   * @type {any[][]}
   */
  libary = []
  constructor() {}

  /**
   * @param {{lib: any[][], isInit?: boolean, maxSameItemCount?: number}} param0
   */
  init(param0) {
    const {lib, isInit = true, maxSameItemCount = 3} = param0
    maxSame = maxSameItemCount

    this.$db.registerTable(tableNameByResult, `./public/output/${tableNameByResult}.json`)
    this.$db.registerTable(tableNameByGroupLib, `./public/output/${tableNameByGroupLib}.json`)

    this.libary = lib
    this.lengthY = lib.length

    if (isInit) {
      fs.writeFileSync(`./public/output/${tableNameByResult}.json`, '')
      fs.writeFileSync(`./public/output/${tableNameByGroupLib}.json`, '')
      this.getGroupResult()
    }
  }

  reset() {
    fs.writeFileSync(`./public/output/${tableNameByResult}.json`, '')
    fs.writeFileSync(`./public/output/${tableNameByGroupLib}.json`, '')
  }

  /** 循环固定图片值组，并将其计算获取排列数据 */
  async getGroupResult() {
    // await this.$db.clear(tableNameByGroupLib)
    /** y轴下标组合
     * @type {number[][]}
     */
    const groupY = Util.choose(Object.keys(this.libary).map(k => Number(k)), maxSame)

    for (const groupPath of groupY) {
      /** @type {string[][]} */
      const curLib = []
      groupPath.forEach(idxY => curLib.push(this.libary[idxY]))

      const func = (idx = 0, data = []) => {
        /** @type {number[][]} */
        const res = curLib[idx].map(k => idx < maxSame - 1 ? func(idx + 1, [...data, k]) : [...data, k])
        return res
      }

      /**
       * @type {string[][]}
       */
      //  @ts-ignore
      const groupXCalcResult = func().flat(maxSame - 1)
      groupXCalcResult.forEach(async group => {
        await this.$db.insert(tableNameByGroupLib, {groupPath, group, exhausted: false})
      })
    }
  }

  /** 循环生成结果，直至无法再次计算出结果
   * @param {{onGetOne: (e: number[]) => void, onEnd: () => void}=} param0
   */
  async loopCreate(param0) {
    try {
      /** 随机取一条固定路径配置
       * @type {{groupPath: number[], group: string[], exhausted: boolean, _id: string}}
       */
      const fixedConfig = await this.$db.findOne(tableNameByGroupLib, {exhausted: false})
      /** 图片路径 */
      const path = []
      /** 历史数库findOne.query，用于筛选出历史记录中所有包含固定路径的数据 */
      const query = {}

      if (!fixedConfig) {     // 若没有可用组，则停止循环
        param0.onEnd && param0.onEnd()
        this.$LoggerInstance.log('所有固定路径使用完成，不再生成数据！')
        return
      }

      fixedConfig.groupPath.forEach((yIdx, xIdx) => {
        query[yIdx] = fixedConfig.group[xIdx] // 设置筛选条件
        path[yIdx] = fixedConfig.group[xIdx]  // 获取可重复路径值
      })

      /** 历史记录中所有包含固定路径的数据 */
      const historyDatas = await this.$db.find(tableNameByResult, query)

      for (let yIdx = 0; yIdx < this.lengthY; yIdx++) {
        if (!fixedConfig.groupPath.includes(yIdx)) {
          const hlib = historyDatas.map(m => m[yIdx])                     // 从历史数据中获取本yIdx的集合
          const clib = this.libary[yIdx].filter(k => !hlib.includes(k))   // 配置中本yIdx排除历史数据之外的集合，保障数据除固定路径外不重复
          path[yIdx] = Util.random(clib)                                  // 从剩余元素中随机抽取作为x
          // this.$LoggerInstance.log(fixedConfig.group, yIdx, hlib, clib)
          if (!path[yIdx]) {
            await this.$db.update(tableNameByGroupLib, {_id: fixedConfig._id}, {...fixedConfig, exhausted: true})
            this.$LoggerInstance.log('本条固定路径使用完成，重新生成一条！')
            this.loopCreate(param0)
            return false
          }
        }
      }

      await this.$db.insert(tableNameByResult, Object.assign({}, path))
      this.$LoggerInstance.log('生成一条数据！', path.join('-'))
      param0.onGetOne && param0.onGetOne(path)
      this.loopCreate(param0)
    } catch (error) {
      // console.log(1, error);
      this.$LoggerInstance.error('循环生成数据失败')
    }
  }
}

module.exports = Creator
